/**
 * 
 */

package com.wutianyi.nio.interfaces.impl;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.util.LinkedList;

import com.wutianyi.nio.interfaces.BufferFactory;
import com.wutianyi.nio.interfaces.ChannelFacade;
import com.wutianyi.nio.interfaces.OutputQueue;

/**
 * @author wutianyi
 * 
 */
public class OutputQueueImpl implements OutputQueue {

	private final BufferFactory				bufferFactory;
	private final ChannelFacade				facade;
	private final LinkedList<ByteBuffer>	queue;
	private ByteBuffer						active	= null;

	public OutputQueueImpl(BufferFactory bufferFactory, ChannelFacade channelFacade) {

		this.bufferFactory = bufferFactory;
		this.facade = channelFacade;
		queue = new LinkedList<ByteBuffer>();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.wutianyi.nio.interfaces.OutputQueue#drainTo(java.nio.channels.ByteChannel)
	 */
	/* (non-Javadoc)
	 * @see com.wutianyi.nio.interfaces.OutputQueue#drainTo(java.nio.channels.ByteChannel)
	 */
	@Override
	public synchronized int drainTo(ByteChannel channel) throws IOException {

		int bytesWritten = 0;

		while(true) {
			if(null == active) {
				if(queue.size() == 0)
					break;
				active = queue.removeFirst();
				active.flip();
			}
			//不一定能保证全部写完
			int rc = channel.write(active);
			bytesWritten += rc;
			if(!active.hasRemaining()) {
				bufferFactory.returBuffer(active);
				active = null;
			}
			if(rc == 0)
				break;
		}

		return bytesWritten;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.wutianyi.nio.interfaces.OutputQueue#enqueue(java.nio.ByteBuffer)
	 */
	@Override
	public synchronized boolean enqueue(ByteBuffer byteBuffer) {

		if(byteBuffer.remaining() == 0) {
			return false;
		}

		if(queue.size() > 0) {
			ByteBuffer tail = queue.getLast();
			if(tail.hasRemaining()) {
				topUpBuffer(tail, byteBuffer);
			}
		}
		while(byteBuffer.hasRemaining()) {
			ByteBuffer newBuf = bufferFactory.newBuffer();
			topUpBuffer(newBuf, byteBuffer);
			queue.addLast(newBuf);
		}
		return false;
	}

	/**
	 * @param tail
	 * @param byteBuffer
	 */
	private void topUpBuffer(ByteBuffer dest, ByteBuffer src) {

		if(src.remaining() <= dest.remaining()) {
			dest.put(src);
		}else {
			while(dest.hasRemaining()) {
				dest.put(src.get());
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.wutianyi.nio.interfaces.OutputQueue#isEmpty()
	 */
	@Override
	public synchronized boolean isEmpty() {

		return (null == active) && (queue.size() == 0);
	}

}
